#include <iostream>
#include <Defines.h>
#include <TimeDiff.h>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
using namespace std;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#ifdef __MAC_OSX__
void clock_gettime( const U32 unused, timespec * tsp ) {
   //
   // NOTE: sizeof( timespec.tv_nsec ) == 8 on Linux
   // NOTE: sizeof( timespec.tv_sec  ) == 8 on Linux
   //
   tsp->tv_nsec = mach_absolute_time();
}
double DiffTimespec( const timespec * beg, const timespec * end ) {

   static mach_timebase_info_data_t info = {0,0};
   if( info.denom == 0 ) {
      mach_timebase_info(&info);
   }
   U64 diff = end->tv_nsec - beg->tv_nsec;
   U64 dnano = diff * ( info.numer / info.denom );
   return 1e-9*((double)dnano);
}
#else
double DiffTimespec( const timespec * beg, const timespec * end ) {
   U64 dsec;
   U64 dnsec;
if( ( end->tv_nsec - beg->tv_nsec ) < 0 ) {
dsec  = end->tv_sec - beg->tv_sec - 1ULL;
dnsec = 1000000000ULL + end->tv_nsec - beg->tv_nsec;
}
else {
dsec  = end->tv_sec  - beg->tv_sec;
dnsec = end->tv_nsec - beg->tv_nsec;
}
   return ((double) dsec) + 1e-9*((double) dnsec);
}
#endif
void AnalyzeRunTimeWallTime( const timespec * clks, const U32 numRuns ) {

   DEBUG_PRINT( "AnalyzeRunTimeWallTime(): numRuns = " << numRuns );
   double min  = 10e10;
   double max  = 0.0;
   double mean = 0.0;
   double std  = 0.0;
   double dt;
   double nr = (double) numRuns;
   
   for( U32 runIdx = 0; runIdx < numRuns; runIdx++ ) {
      const timespec * clk0 = clks + 2*runIdx + 0;
      const timespec * clk1 = clks + 2*runIdx + 1;

      double diff = DiffTimespec( clk0, clk1 );
      
      mean += diff;
      if( diff < min ) { min = diff; }
      if( diff > max ) { max = diff; }
   }
   mean /= nr;
   for( U32 runIdx = 0; runIdx < numRuns; runIdx++ ) {
      const timespec * clk0 = clks + 2*runIdx + 0;
      const timespec * clk1 = clks + 2*runIdx + 1;
      dt = DiffTimespec( clk0, clk1 ) - mean;
      std += (dt*dt);
   }
   std = sqrt( std / nr );
   printf( "mean = %f [msec.]\n", 1000.0*mean );
   printf( "std  = %f [msec.]\n", 1000.0*std  );
   printf( "min  = %f [msec.]\n", 1000.0*min  );
   printf( "max  = %f [msec.]\n", 1000.0*max  );
}
void AnalyzeRunTimeCPUTime( const vector< timespec * > & clks, const U32 numRuns, const U32 numThreads ) { // -- original --, const U32 numKernelsPerThread ) {

   DEBUG_PRINT( "AnalyzeRunTime()" );
   
   U32 i;
   vector< double > runTimes;

   for( i = 0; i < numRuns; i++ ) {
      
      double maxTime = 0.0;
      
      for( U32 tidx = 0; tidx < numThreads; tidx++ ) {
         
         timespec * pclk = clks[ tidx ];
         
         timespec * clk0 = pclk + 0;
         timespec * clk1 = pclk + 1;
         
         double runTime = DiffTimespec( clk0, clk1 );
         if( runTime > maxTime ) {
            runTimes.push_back( runTime );
         }
      }
   }
   
   double min  = 10e10;
   double max  = 0.0;
   double mean = 0.0;
   double std  = 0.0;
   
   const double nr = (double) numRuns;

   for( i = 0; i < numRuns; i++ ) {
      double t = runTimes[ i ];
      mean += t;
      if( t < min ) { min = t; }
      if( t > max ) { max = t; }
   }
   mean /= nr;
   
   for( i=0; i < numRuns; i++ ) {
      double t = runTimes[ i ];
      double dt = t - mean;
      std += (dt*dt);
   }
   std = sqrt( std / nr );
   printf( "mean = %f [msec.]\n", 1000.0*mean );
   printf( "std  = %f [msec.]\n", 1000.0*std  );
   printf( "min  = %f [msec.]\n", 1000.0*min  );
   printf( "max  = %f [msec.]\n", 1000.0*max  );
}
//#else
//void AnalyzeRunTime( timespec * clks, int numRuns ) {
//  int i;
//  double mean = 0.0;
//  double std  = 0.0;
//  double dt;
//  double nr = (double) numRuns;
//
//  for( i=0; i < numRuns; i++ ) {
//    mean += DiffTimespec( clks+i, clks+i+1 );
//  }
//  mean /= nr;
//  for( i=0; i < numRuns; i++ ) {
//    dt = DiffTimespec( clks+i, clks+i+1 ) - mean;
//    std += (dt*dt);
//  }
//  std = sqrt( std / nr );
//  printf( "mean = %f [msec.]\n", 1000.0*mean );
//  printf( "std  = %f [msec.]\n", 1000.0*std  );
//}
//#endif
